﻿#pragma once
#include <QSemaphore>
#include <QMutexLocker>
#include <QDebug>


template <typename T>
class CQueueRT
{
public:

	CQueueRT(unsigned int MaxCount = 10);
	virtual ~CQueueRT(void);
	bool write(T *pImgInfo);
	T* read();
	T* readLastOne();
	T* peek();
	bool read(T *pbuf);
	unsigned long getReadIndex();
	unsigned long getWriteIndex() ;
	void InitQueueWithSize(unsigned int nSize);
	void Reset();  
	bool Clear();  // 应用与刷新界面较慢时 置位
	void Destroy();
	bool HaveData();
	unsigned long Queen_UsedLen(void);
	unsigned long Queen_FreeLen(void);
	void pushHeapData(T *pImgInfo, int nIndex);
	T *freeHeapData(int nIndex);
	T * PreWrite();  // 预先读出一个 元素
	void EndWrite(bool bMovePos = true); // 移动写指针
	T* PreWrite_WO();  // 只写模式
	void EndWrite_WO(T*); // 只写模式
	T * GetDataAt(int n);  // 预先读出一个 元素
	int QueenSize()
	{
		return m_MaxCount;
	}

	unsigned long GetAvailableNum()
	{
		return m_hFull.available();
	}


	unsigned long GetFreeAvailableNum()
	{
		return m_hEmpty.available();
	}

protected:

	unsigned long _inline_Queen_UsedLen(void);
	unsigned long _inline_Queen_FreeLen(void);

private:

	T *m_pObj;
	unsigned int m_MaxCount;
	unsigned long m_ReadIndex;
	unsigned long m_WriteIndex;
	QVector<bool> m_vbDirty;
	QVector<T*> m_vData;
	QMutex m_Lock;
	QSemaphore m_hFull;
	QSemaphore m_hEmpty;
	bool m_bInit;
};

template <typename T>
bool CQueueRT<T>::HaveData()
{
	if (m_hFull.available() > 0)
	{
		return true;
	}

	return false;
}


template <typename T>
T * CQueueRT<T>::GetDataAt(int n)
{
	if (!m_bInit)
	{
		return NULL;
	}

	if (n == m_MaxCount)
	{
		return NULL;
	}

	return &m_pObj[n%m_MaxCount];
}

template <typename T>
void CQueueRT<T>::Reset()
{
	QMutexLocker lock(&m_Lock);
	m_ReadIndex = 0;
	m_WriteIndex = 0;
	
	qDebug() << "Reset Max:" << m_MaxCount << " Avlid:" << m_hEmpty.available();
	
	if (m_MaxCount > m_hEmpty.available())
	{
		m_hEmpty.release(m_MaxCount - m_hEmpty.available());  // qt 获取se数量存在bug
	}
	else
	{
		m_hEmpty.tryAcquire(m_hEmpty.available() - m_MaxCount, 10);
	}

	if (m_hFull.available())
	{
		m_hFull.tryAcquire(m_hFull.available(), 10);
	}

	qDebug() << "---> CQueueRT::Reset Empty:" << m_hEmpty.available()
	<< " Full:" << m_hFull.available();
}


template<typename T>
bool CQueueRT<T>::Clear(void)
{
	if (!m_hFull.tryAcquire(1, 40))
	{
		return false;
	}

	QMutexLocker lock(&m_Lock);
	qDebug() << "Clear Max:" << m_MaxCount << " Avlid:" << m_hEmpty.available();
	m_ReadIndex = m_WriteIndex;
	if (m_MaxCount - m_hEmpty.available() > 0)
	{
		m_hEmpty.release(m_MaxCount - m_hEmpty.available());
	}
	

	if (m_hFull.available())
	{
		m_hFull.tryAcquire(m_hFull.available(), 10);
	}

 	qDebug() << "Clear Empty:" << m_hEmpty.available()
 	<< " Full:" << m_hFull.available()
 	 	<< " FreeLen:" << _inline_Queen_FreeLen();

	return true;
}


template <typename T>
void CQueueRT<T>::Destroy()
{
	if (!m_bInit)
	{
		return;
	}

	QMutexLocker lock(&m_Lock);
	m_ReadIndex = 0;
	m_WriteIndex = 0;
	delete[] m_pObj;
	m_bInit = false;
}

template <typename T>
T* CQueueRT<T>::peek()
{
	if (m_ReadIndex == m_WriteIndex)
		return NULL;

	QMutexLocker lock(&m_Lock);

	return &m_pObj[m_ReadIndex%m_MaxCount];
}

template<typename T>
CQueueRT<T>::CQueueRT(unsigned int MaxCount):m_ReadIndex(0),
m_WriteIndex(0), m_MaxCount(MaxCount)
{
	m_bInit = false;
}

template<typename T>
CQueueRT<T>::~CQueueRT(void)
{
	Destroy();
}

template<typename T>
void CQueueRT<T>::InitQueueWithSize(unsigned int nSize) 
{
	// 创建信标内核对象 及 初始化 关键代码代码段区域
	QMutexLocker lock(&m_Lock);

	m_bInit = false;

	if(nSize != 0)
	{
		m_MaxCount = nSize;
	}

	m_pObj = new T[m_MaxCount];
	m_vbDirty = QVector<bool>(m_MaxCount, false);
	m_vData.resize(m_MaxCount);
	for (int i = 0; i < m_MaxCount; i++)
	{
		m_vData[i] = &m_pObj[i];
	}

	m_ReadIndex = 0;
	m_WriteIndex = 0;

	qDebug() << "Init Max:" << m_MaxCount << " Avlid:" << m_hEmpty.available();

	if (m_MaxCount > m_hEmpty.available())
	{
		m_hEmpty.release(m_MaxCount - m_hEmpty.available());  // qt 获取se数量存在bug
	}
	else
	{
		m_hEmpty.tryAcquire(m_hEmpty.available() - m_MaxCount, 10);
	}

	if (m_hFull.available())
	{
		m_hFull.tryAcquire(m_hFull.available(), 10);
	}

	qDebug() << "---> CQueueRT::Init Empty:" << m_hEmpty.available()
		<< " Full:" << m_hFull.available();
	m_bInit = true;

	return;
}

// 重要： 在完成当前数据时 其他线程不能再共享当前的 写 索引 [3/27/2017 ejitec]
template<typename T>
T * CQueueRT<T>::PreWrite()
{
	if (!m_hEmpty.tryAcquire(1, 40))
	{
		return NULL;
	}

	QMutexLocker lock(&m_Lock);
	
	if (m_ReadIndex == (m_WriteIndex + 1) % m_MaxCount)  // 将 写满时等待，避免 use_len = 0 ，此逻辑在 只写不读时 有可能死循环
	{
		m_hEmpty.release();

		return NULL;
	}

	return &m_pObj[m_WriteIndex%m_MaxCount];
}

template<typename T>
void CQueueRT<T>::EndWrite(bool bRW)
{
	QMutexLocker lock(&m_Lock);

	if (!bRW)
	{
		m_hEmpty.release();

		return;
	}
	else
	{
		++m_WriteIndex;
		m_WriteIndex %= m_MaxCount;
		m_hFull.release();
	}
}

template<typename T>
T* CQueueRT<T>::PreWrite_WO()
{
	if (!m_hEmpty.tryAcquire(1, 40))
	{
		return NULL;
	}

	QMutexLocker lock(&m_Lock);

	if (m_vbDirty[m_WriteIndex%m_MaxCount])
	{
		int i = 0;
		for (auto& it : m_vbDirty)
		{
			if (it)
			{
				m_WriteIndex = i;
				it = true;
				break;
			}
			++i;
		}
	}

	m_vbDirty[m_WriteIndex] = true;
	int Idx = m_WriteIndex%m_MaxCount;
	T* tmp = &m_pObj[Idx];

	++m_WriteIndex;
	m_WriteIndex %= m_MaxCount;

	return tmp;
}

template<typename T>
void  CQueueRT<T>::EndWrite_WO(T* t)
{
	QMutexLocker lock(&m_Lock);
	auto it = std::find(m_vData.begin(), m_vData.end(), t);
	int nIdx = std::distance(m_vData.begin(), it);
	m_vbDirty[nIdx] = false;
	m_hEmpty.release();
}

 template <typename T>
 void CQueueRT<T>::pushHeapData(T *pImgInfo, int nIndex)
 {
	 if (nIndex >= m_MaxCount && !m_bInit)
	 {
		 return;
	 }

	 memcpy(&m_pObj[nIndex%m_MaxCount], pImgInfo, sizeof(T));
 }

 template <typename T>
 T * CQueueRT<T>::freeHeapData(int nIndex)
 {
	 if (nIndex >= m_MaxCount && !m_bInit)
	 {
		 return NULL;
	 }

	 return &m_pObj[nIndex];
 }

 // 
template<typename T>
bool CQueueRT<T>::write(T *pImgInfo)
{
	if (!m_hEmpty.tryAcquire(1, 40) /*|| m_ReadIndex == (m_WriteIndex + 1) % m_MaxCount*/)
	{
		return false;
	}

	QMutexLocker lock(&m_Lock);

	memcpy(&m_pObj[m_WriteIndex%m_MaxCount], pImgInfo, sizeof(T));
	m_WriteIndex++;
	m_WriteIndex %= m_MaxCount;
	m_hFull.release();  // P

	return true;
}

template<typename T>
T* CQueueRT<T>::read()
{
	if (!m_hFull.tryAcquire(1, 40))
	{
		return NULL;
	}

	QMutexLocker lock(&m_Lock);

	T* tmp = &m_pObj[m_ReadIndex%m_MaxCount];
	m_ReadIndex++;
	m_ReadIndex %= m_MaxCount;
	m_hEmpty.release();

	return tmp;
}

template<typename T>
T* CQueueRT<T>::readLastOne()
{
	if (!m_hFull.tryAcquire(1, 40) || m_ReadIndex == m_WriteIndex)
	{
		return NULL;
	}

	QMutexLocker lock(&m_Lock);

	int nIndex = (m_WriteIndex - 1 + m_MaxCount) % m_MaxCount;  // 默认写较快
	T* tmp = &m_pObj[nIndex];
	int nPlus = (nIndex - m_ReadIndex + m_MaxCount) % m_MaxCount;
	// 移动到尾部
	m_ReadIndex = nIndex;
	m_hEmpty.release(nPlus); 
	m_hFull.tryAcquire(nPlus -1,40);

	return tmp;
}

template<typename T>
bool CQueueRT<T>::read(T *pbuf)
{
	if (!m_hFull.tryAcquire(1, 40))
	{
		return false;
	}

	if (m_ReadIndex == m_WriteIndex)
		return false;

	QMutexLocker lock(&m_Lock);
	
	memcpy(pbuf, &m_pObj[m_ReadIndex%m_MaxCount], sizeof(T));
	m_ReadIndex++;
	m_ReadIndex %= m_MaxCount;
	m_hEmpty.release();

	return true;
}

template<typename T>
unsigned long CQueueRT<T>::getReadIndex()
{
	return m_ReadIndex;
}

template<typename T>
unsigned long CQueueRT<T>::getWriteIndex() 
{
	return m_WriteIndex;
}

template<typename T>
unsigned long CQueueRT<T>::Queen_UsedLen(void)
{
	QMutexLocker lock(&m_Lock);

	return _inline_Queen_UsedLen();
}

template<typename T>
unsigned long CQueueRT<T>::Queen_FreeLen(void)
{
	QMutexLocker lock(&m_Lock);
	
	return _inline_Queen_FreeLen();
}

template <typename T>
unsigned long CQueueRT<T>::_inline_Queen_FreeLen(void)
{
	return ((m_MaxCount + m_ReadIndex - m_WriteIndex) % m_MaxCount);  // 包含读在写后 和写在读后2种情况
}

template <typename T>
unsigned long CQueueRT<T>::_inline_Queen_UsedLen(void)
{
	return ((m_MaxCount + m_WriteIndex - m_ReadIndex) % m_MaxCount);  // 包含读在写后 和写在读后2种情况
}